/* 
 * File:   Inter.cpp
 * Author: kuba, weeteck
 * 
 * Created on 9. listopad 2012, 23:37
 */

#include <cstdlib>
#include <signal.h>
#include <unistd.h>
#include <string.h>
#include <readline/history.h>
#include <limits.h>
#include "JobControl.h"
#include "Job.h"
#include "Inter.h"

using std::list;


/**
 * Vestaveny prikaz shellu "exit".
 * Funkce provede potrebne uklidove akce a ukonci shell.
 */
void Inter::exit_shell()
{
  char hist_fname[PATH_MAX];

  snprintf(hist_fname, PATH_MAX, "%s/%s", getenv("HOME"), HISTORY_FILENAME);
  if (write_history(hist_fname))
    perror("write_history");
  clear_history();
  printf("exit\n");

  if (jobs_list.empty())
    exit(0);
  else
    printf("%s\n", STR_UNFIN_JOBS);
}


/**
 * Vestaveny prikaz shellu "cd". Změní pracovní adresář.
 * 
 * @param args Argumenty z prikazove radky.
 * @param nargs Počet argumentu (včetne nazvu prikazu).
 */
void Inter::cd(char* args[], int nargs)
{
  char* path;

  if (nargs == 1)
    path = getenv("HOME"); // pokud nezadal cestu -> domu
  else
    path = args[1];
  if (chdir(path))
    perror("cd");
}


/**
 * ZRUŠENO
 * Funkce pro vypsani aktualniho pracovniho adresare.
 * @param MAX_PROMPT_LEN maximální délka příkazové řádky
 */
/*void Inter::pwd(const int MAX_PROMPT_LEN)
{	
  char cwd[MAX_PROMPT_LEN];
  memset(cwd,'\0', MAX_PROMPT_LEN);
  getcwd(cwd, MAX_PROMPT_LEN);
  printf("%s\n", cwd);
}*/


/**
 * Vestaveny prikaz shellu "bg".
 * Funkce prepne ulohu na pozadi, jako by byla spustena s &.
 * Pokud neni argumentem specifikovano id ulohy, prepne na pozadi ulohu o ktere si shell
 * mysli, ze je aktualni.
 * 
 * @param args  Argumenty z prikazove radky.
 * @param nargs Pocet argumentu (vcetne samotneho prikazu bg).
 */
void Inter::bg(char* args[], int nargs)
{
  Job* job;

  if (jobs_list.empty())
  {
    printf("%s\n", STR_NO_JOB);
    return;
  }
  job = (nargs == 1) ? fndjob_id(-1) : fndjob_id(atoi(args[1]));
  if (job == NULL)
  {
    printf("%s [%s]\n", STR_NO_JOB, args[1]);
    return;
  }

  // spustime ulohu na pozadi
  printf("[%d]  %s &\n", job->getId(), job->getCmd());
  job->setState(Job::RUNNING);
  kill(-job->getPgid(), SIGCONT);
}


/**
 * Vestaveny prikaz shellu "fg".
 * Funkce prepne ulohu na popredi, jako by byla normalne spustena.
 * Pokud neni argumentem specifikovano id ulohy, prepne na popredi ulohu o ktere si shell
 * mysli, ze je aktualni.
 * 
 * @param args  Argumenty z prikazove radky.
 * @param nargs Pocet argumentu (vcetne samotneho prikazu fg).
 */
void Inter::fg(char* args[], int nargs)
{
  Job* job;
  int status;

  if (jobs_list.empty())
  {
    printf("%s\n", STR_NO_JOB);
    return;
  }
  job = (nargs == 1) ? fndjob_id(-1) : fndjob_id(atoi(args[1]));
  if (job == NULL)
  {
    printf("%s [%s]\n", STR_NO_JOB, args[1]);
    return;
  }

  // spustime ulohu na popredi
  printf("[%d]  %s\n", job->getId(), job->getCmd());
  job->setState(Job::RUNNING);
  kill(-job->getPgid(), SIGCONT);
  status = wait_for_child(job->getPgid());
  if (test_child_status(status, job) == Job::STOPPED)
    job->setState(Job::STOPPED);
  else
    deljob(job);
}


/**
 * Vestaveny prikaz shellu "jobs".
 * Funkce vypise vsechny spustene ulohy.
 */
void Inter::jobs()
{
  list<Job*>::const_iterator iter;
  Job* jbp;
  Job::State state;
  const char* state_str;

  for (iter = jobs_list.begin(); iter != jobs_list.end(); iter++)
  {
    jbp = *iter;
    state = jbp->getState();
    state_str = STR_STATE[state];
    printf("[%d]  %-11s  %s  (%s: %d)\n", jbp->getId(), state_str, jbp->getCmd(),
                                          jbp->isPiped() ? "pgid" : "pid", jbp->getPgid());
  }
}


/**
 * Vestaveny prikaz shellu "history".
 * Funkce vypise polozky ulozene v historii prikazu.
 */
void Inter::history()
{
  HIST_ENTRY** list;

  list = history_list();
  for (int i = 0; list[i] != NULL; i++)
  {
    printf("%s\n", list[i]->line);
  }
}


/**
 * Vestaveny prikaz shellu "help".
 * Funkce vypisuje napovedu k jednotlivym prikazum shellu.
 * 
 * @param args  Argumenty z prikazove radky.
 * @param nargs Pocet argumentu (vcetne prikazu help).
 */
void Inter::help(char* args[], int nargs)
{
  char *command;
  const char *helpstr;
  
  if (nargs == 1)
    helpstr = HELP;
  else
  {
    command = args[1];
    if (!strcmp(command, "bg"))
      helpstr = HELP_BG;
    else if (!strcmp(command, "cd"))
      helpstr = HELP_CD;
    else if (!strcmp(command, "exit"))
      helpstr = HELP_EXIT;
    else if (!strcmp(command, "fg"))
      helpstr = HELP_FG;
    else if (!strcmp(command, "help"))
      helpstr = HELP_HELP;
    else if (!strcmp(command, "history"))
      helpstr = HELP_HISTORY;
    else if (!strcmp(command, "jobs"))
      helpstr = HELP_JOBS;
    else
    {
      printf("help: %s \"%s\".\n      %s \"man %s\".\n", HELP_UNKNOWN1, command, HELP_UNKNOWN2, command);
      return;
    }
  }
  
  printf("%s\n", helpstr);
}
